/*
 * Copyright 2013 Agustina Martinez-Garcia

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package uk.ljmu.qudexapps.manager.services;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.log4j.Logger;
import org.igfay.jfig.JFigException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;






//import uk.ljmu.metadata.schemas.SchemaInstanceContainer;
import uk.ljmu.metadata.utilities.Constants;
import uk.ljmu.metadata.utilities.MetadataUtilities;
import uk.ljmu.qudexapps.manager.domain.FilesModel;
import uk.ljmu.qudexapps.manager.domain.Relation;
import uk.ljmu.qudexapps.manager.utilities.GeneralUtilities;
import uk.ljmu.qudexapps.xmllib.exceptions.FoxmlException;
import uk.ljmu.qudexapps.xmllib.model.CollectionElement;
import uk.ljmu.qudexapps.xmllib.services.FedoraMulgaraService;
import uk.ljmu.qudexapps.xmllib.services.FedoraMulgaraServiceImpl;
//import uk.ljmu.qudexapps.xmllib.services.QudexFoxmlService;
//import uk.ljmu.qudexapps.xmllib.services.QudexFoxmlServiceImpl;
import uk.ljmu.qudexapps.xmllib.utilities.IngestionResults;

@Service("spreadsheetService")
public class SpreadsheetServiceImpl implements SpreadsheetService {
	/**
     * 
     */
	@SuppressWarnings("unused")
	private static final long serialVersionUID = -1468747790352243151L;

	private static Logger logger = Logger
			.getLogger(SpreadsheetServiceImpl.class);
	/**
	 * ATTRIBUTES
	 */

	private String fileSeparator = System.getProperty("file.separator");

	@Autowired
	private FilesModel files;
	
	//transient private QudexFoxmlService ifz = null;

	private static String JQUERY_BIT;
	
	@Autowired
	/**
	 * the MessageSource object for internationalised/localised messages
	 */
	MessageSource messageSource;

	static {
		StringBuilder sb = new StringBuilder();
		sb.append("<script type=\"text/javascript\">\n");
		sb.append("	$(document).ready(function () {\n");
		sb.append("     $('ul.tree li:last-child').addClass('last');\n");
		sb.append("	});\n");
		sb.append("</script>\n");
		JQUERY_BIT = sb.toString();
	}

	public String getRelationResults() {
		return this.files.getRelationResults();
	}

	public void setRelationResults(String relationResults) {
		this.files.setRelationResults(relationResults);
	}

	/**
	 * @param ifz
	 *            the ifz to set
	 *//*
	public void setIfz(QudexFoxmlService ifz) {
		files.getIfz() = ifz;
	}

	*//**
	 * @return the ifz
	 *//*
	public QudexFoxmlService getIfz() {
		return ifz;
	}*/

	/**
	 * Assigns the file type of the upload: CSV or Excel files
	 * 
	 * @param fileType
	 */
	public void setFileType(String fileType) {
		this.files.setFileType(fileType);
	}

	/**
	 * Returns the type of the uploaded file
	 * 
	 * @return
	 */
	public String getFileType() {
		return this.files.getFileType();
	}

	public void setFiles(FilesModel files) {
		this.files = files;
	}

	public FilesModel getFiles() {
		return files;
	}

	public String getWorkingQudexRootCollection() {
		return this.files.getWorkingQudexRootCollection();
	}

	public void setWorkingQudexRootCollection(String workingQudexRootCollection) {
		this.files.setWorkingQudexRootCollection(workingQudexRootCollection);
	}

	//public SpreadsheetServiceImpl() throws FoxmlException, JFigException {
	//	files.getIfz() = new QudexFoxmlServiceImpl("", true);
	//}

	public void initialiseFilesModel() {
		files.setTreeList(files.getIfz().getQudexCollectionsTree());
		files.setWorkingQudexRootCollection("");
	}

	public List<IngestionResults> ingestCollectionsSpreadsheet()
			throws FoxmlException, IOException, Exception {

		files.getIfz().setObjResults(new ArrayList<IngestionResults>());
		files.getIfz().setQudexCollections(true);
		if (files.getSpreadsheet().getOriginalFilename() != "") {
			// SchemaInstanceContainer container = new
			// SchemaInstanceContainer();
			files.getIfz().setFileType(files.getSpreadsheet().getContentType());
			files.getIfz().setOriginalSpreadsheetName(files.getSpreadsheet()
					.getOriginalFilename());
			files.getIfz().ingestQudexCollectionsSpreadsheet(this.cleanCollectionIds(files
					.getCollectionsIds()), files.getSpreadsheet()
					.getInputStream());
			// Clean resources
			// container.getListSchemaInstances().clear();
		}
		return files.getIfz().getObjResults();
	}

	/**
	 * Ingest a qudex file-level spreadsheet into the repository
	 * 
	 * @param path
	 *            spreadsheet directory path
	 * 
	 * @return list with ingestion results
	 */
	public List<IngestionResults> ingestFilesSpreadsheet()
			throws FoxmlException, IOException, Exception {

		files.getIfz().setObjResults(new ArrayList<IngestionResults>());
		files.getIfz().setQudexCollections(false);
		if (files.getSpreadsheet().getOriginalFilename() != "") {
			// SchemaInstanceContainer container = new
			// SchemaInstanceContainer();
			files.getIfz().setFileType(files.getSpreadsheet().getContentType());
			files.getIfz().setOriginalSpreadsheetName(files.getSpreadsheet()
					.getOriginalFilename());
			// TODO CHECK IF COLLECTIONS PARAMETER IS NEEDED
			files.getIfz().ingestFileLevelSpreadsheet(
					this.cleanCollectionIds(this.getFiles().getCollectionsIds()),
					files.getModifiedSpreadsheet() != null ? files
							.getModifiedSpreadsheet() : files.getSpreadsheet()
							.getInputStream());
			// ifz.ingestFileLevelSpreadsheet(files.getSpreadsheet().getInputStream());
			// Clean resources
			// container.getListSchemaInstances().clear();
		}
		return files.getIfz().getObjResults();
	}

	@SuppressWarnings("unused")
	private String returnFileExtension(String contentType) {
		if (contentType.equals("text/csv"))
			return ".csv";
		else if (contentType.equalsIgnoreCase("application/vnd.ms-excel")
				|| contentType.equalsIgnoreCase("application/ms-excel"))
			return ".xsl";
		else
			return "";
	}

	public List<IngestionResults> getResults() {
		return files.getIfz().getObjResults();
	}

	// PRIVATE FUNCTIONS
	private List<String> cleanCollectionIds(String collectionList) {
		String[] listIds = collectionList.split(Constants.LIST_SEP);
		int i = 0;
		if (listIds.length > 0) {
			for (String str : listIds) {
				if (str.contains(MetadataUtilities.OBJECTID))
					listIds[i] = str.replace(MetadataUtilities.OBJECTID, "");
				i++;
			}
			return GeneralUtilities.removeElements(listIds,
					uk.ljmu.qudexapps.xmllib.utilities.Constants.NOCOLLECTION);
		}

		return new ArrayList<String>();
	}

	public String getProgress() {
		return files.getIfz().getProgressStatus();
	}

	public void setQudexCollections(boolean qudexCollections) {
		files.getIfz().setQudexCollections(qudexCollections);

	}

	public List<String> getQudexCollections() {
		return files.getIfz().getQudexCollections(this
				.getWorkingQudexRootCollection());
	}

	public List<CollectionElement> getQudexCollectionsTree() {
		return this.files.getTreeList();
	}

	// Print Subtree
	public List<String> printSubtree(String collectionId) {
		Locale locale = LocaleContextHolder.getLocale();
		cleanDisplay();
		List<String> auxList = new ArrayList<String>();
		if (collectionId.equals("NULLVALUE")) {
			this.files.getHtmlSubTree().delete(0,
					this.files.getHtmlSubTree().length());
			auxList.add("");
			auxList.add("");
			return auxList;
		}
		// Find Root collection Node of the actual node
		String initialNode = files.getIfz().getQudexRootParent(collectionId.replace(
				MetadataUtilities.OBJECTID, ""));
		// CollectionElement auxNode =
		// CollectionElement.findElement(collectionId
		// .replace(MetadataUtilities.OBJECTID, ""), this.treeList);
		// String replaceId = "";
		// AMG - trick to avoid printing the child node twice since it has
		// relation to the immediate parent and also to its root collection
		// if (auxNode.getImmediateParents().size() > 1) {
		// for (String parent : auxNode.getImmediateParents()) {
		// if (parent.equals(initialNode.replace(
		// MetadataUtilities.OBJECTID, ""))) {
		// replaceId = collectionId.replace(
		// MetadataUtilities.OBJECTID, "");
		// break;
		// }
		// }
		// }
		if (initialNode != null) {
			CollectionElement collectionNode = CollectionElement.findElement(
					initialNode.replace(MetadataUtilities.OBJECTID, ""),
					this.files.getTreeList());
			if (collectionNode == null) {
				this.files.getHtmlSubTree().append(
						"<div id=\"printTree\" class=\"example\">\n");
				this.files.getHtmlSubTree().append("ERROR TREE NULL");
				this.files.getHtmlSubTree().append("</div>\n");
				auxList.add(this.files.getHtmlSubTree().toString());
				auxList.add(collectionId);
				this.files.getHtmlSubTree().delete(0,
						this.files.getHtmlSubTree().length());
				return auxList;
			}
			this.files.getHtmlSubTree().delete(0,
					this.files.getHtmlSubTree().length());
			this.files.getHtmlSubTree().append(JQUERY_BIT);
			this.files.getHtmlSubTree().append(messageSource.getMessage("tree.structure", null, locale));
			//this.files.getHtmlSubTree().append(
			//		"<div id=\"printTree\" class=\"example\">\n");
			this.files.getHtmlSubTree().append(
					"<ul class=\"tree\" id=\"tree\">\n");
			// traverseTree(collectionNode, 1, replaceId, collectionId.replace(
			// MetadataUtilities.OBJECTID, ""));
			traverseTree(collectionNode, 1,
					collectionId.replace(MetadataUtilities.OBJECTID, ""));
			this.files.getHtmlSubTree().append("</ul>\n");
			//this.files.getHtmlSubTree().append("</div>\n");
		} else {
			CollectionElement collectionNode = CollectionElement.findElement(
					collectionId.replace(MetadataUtilities.OBJECTID, ""),
					this.files.getTreeList());
			// Root Collection
			this.files.getHtmlSubTree().delete(0,
					this.files.getHtmlSubTree().length());
			this.files.getHtmlSubTree().append(JQUERY_BIT);
			this.files.getHtmlSubTree().append(
					"<h4>Selected collection navigation</h4>");
			this.files
					.getHtmlSubTree()
					.append("<p>The selected collection presents the following structure in the repository:</p>");
			this.files.getHtmlSubTree().append(
					"<div id=\"printTree\" class=\"example\">\n");
			this.files.getHtmlSubTree().append(
					"<p>The collection with title: &quot;<b>"
							+ collectionNode.getCollectionTitle()
							+ "</b>&quot; is a Collection Container</p>");
			this.files.getHtmlSubTree().append("</div>\n");
		}
		auxList.add(this.files.getHtmlSubTree().toString());
		auxList.add(collectionId);
		this.files.getHtmlSubTree().delete(0,
				this.files.getHtmlSubTree().length());
		return auxList;
	}

	/*
	 * private void traverseTree(CollectionElement currentElement, int depth,
	 * String excludeNodeId, String highlight) { // int j; String skip = ""; //
	 * Opening LI if (currentElement.getCollectionId().equals(highlight))
	 * this.htmlSubTree.append("<li class=\"highlight\">\n"); else
	 * this.htmlSubTree.append("<li>\n");
	 * this.htmlSubTree.append(currentElement.getCollectionTitle());
	 * this.htmlSubTree.append(" (Repository identifier: ");
	 * this.htmlSubTree.append(currentElement.getCollectionId());
	 * this.htmlSubTree.append(")"); this.htmlSubTree.append("\n"); // Traverse
	 * the tree int i = 0; String currentElementChild = ""; if (excludeNodeId !=
	 * "") { for (String child : currentElement.getImmediateChildren()) { if
	 * (child.equals(excludeNodeId)) { skip = excludeNodeId;
	 * currentElement.getImmediateChildren().add(0, skip);
	 * currentElement.getImmediateChildren().remove(child); excludeNodeId = "";
	 * break; } } } if (currentElement.getImmediateChildren().size() > 0) {
	 * currentElementChild = currentElement.getImmediateChildren().get(i); //
	 * SUB UL this.htmlSubTree.append("<ul>\n"); while (i <
	 * currentElement.getImmediateChildren().size()) { if
	 * (currentElementChild.equals(skip)) { i++; if (i <
	 * currentElement.getImmediateChildren().size()) currentElementChild =
	 * currentElement.getImmediateChildren().get(i); continue; } // Recursively
	 * traverse the tree structure of the child node
	 * traverseTree(CollectionElement.findElement(currentElementChild,
	 * this.treeList), depth + 1, excludeNodeId, highlight); i++; if (i <
	 * currentElement.getImmediateChildren().size()) currentElementChild =
	 * currentElement.getImmediateChildren() .get(i); }
	 * this.htmlSubTree.append("</ul>\n"); // CLOSE SUB UL }
	 * this.htmlSubTree.append("</li>\n"); }
	 */
	private void traverseTree(CollectionElement currentElement, int depth,
			String highlight) {
		if (!currentElement.isDisplayed()) {
			currentElement.setDisplayed(true);
			// Opening LI
			if (currentElement.getCollectionId().equals(highlight))
				this.files.getHtmlSubTree()
						.append("<li class=\"highlight\">\n");
			else
				this.files.getHtmlSubTree().append("<li>\n");
			this.files.getHtmlSubTree().append(
					currentElement.getCollectionTitle());
			this.files.getHtmlSubTree().append(" (Repository identifier: ");
			this.files.getHtmlSubTree()
					.append(currentElement.getCollectionId());
			this.files.getHtmlSubTree().append(")");
			this.files.getHtmlSubTree().append("\n");
			// Traverse the tree
			int i = 0;
			String currentElementChild = "";

			if (currentElement.getImmediateChildren().size() > 0) {
				currentElementChild = currentElement.getImmediateChildren()
						.get(i);
				// SUB UL
				this.files.getHtmlSubTree().append("<ul>\n");
				while (i < currentElement.getImmediateChildren().size()) {
					// Recursively traverse the tree structure of the child node
					traverseTree(CollectionElement.findElement(
							currentElementChild, this.files.getTreeList()),
							depth + 1, highlight);
					i++;
					if (i < currentElement.getImmediateChildren().size())
						currentElementChild = currentElement
								.getImmediateChildren().get(i);
				}
				this.files.getHtmlSubTree().append("</ul>\n"); // CLOSE SUB UL
			}
			this.files.getHtmlSubTree().append("</li>\n");
		}
	}

	public void cleanDisplay() {
		for (CollectionElement elem : this.files.getTreeList()) {
			elem.setDisplayed(false);
		}
	}

	public void regenerateTree() {
		this.files.setTreeList(files.getIfz().getQudexCollectionsTree());
	}

	public void deleteFile() {
		String fullPath = (files.getTempDirPath().endsWith(this.fileSeparator)) ? files
				.getTempDirPath()
				+ files.getSpreadsheet().getOriginalFilename() : files
				.getTempDirPath()
				+ this.fileSeparator
				+ files.getSpreadsheet().getOriginalFilename();
		File file = new File(fullPath);
		file.delete();
	}

	public void setOriginalSpreadsheetPath(String path) {
		files.getIfz().setOriginalSpreadsheetPath(path);
	}

	public void destroy() {
		if (files.getIfz() != null) {
			files.getIfz().cleanFullInstance();
		}
	}

	public void init() {

	}

	@Override
	public List<String> getQudexRootCollections() {
		return files.getIfz().getQudexRootCollections();
	}

	@Override
	public List<String> getQudexInstanceCollections() {
		return files.getIfz().getQudexInstanceCollections();
	}

	@Override
	public List<String> getQudexCollectionDocuments() {
		return files.getIfz().getQudexCollectionDocuments(this
				.getWorkingQudexRootCollection());
	}

	@Override
	public void addFedoraRelation(Relation relationObject) {
		// TODO Auto-generated method stub
		String results = files.getIfz().getFedoraObject()
				.addRelationship(
						relationObject.getSubjectRelation().replace(
								"info:fedora/", ""),
						relationObject.getSubjectRelation(),
						"http://example.org/qudex/"
								+ relationObject.getRelationName(),
						relationObject.getObjectRelation(), "false", "");
		if (results == null) {
			System.out.println("ERROR REL NOT CREATED");
			this.setRelationResults("Relationship not created! Error(s) ocurred. Check Application log.");
		} else {
			String title = files.getIfz().getTitle(relationObject
					.getSubjectRelation());
			String title2 = files.getIfz().getTitle(relationObject
					.getObjectRelation());
			String sms = "<p>Relationship added:</p>"
					+ "<p> Relation subject: " + title
					+ "</p><p>Relation name: "
					+ relationObject.getRelationName()
					+ "</p><p>Relation object: " + title2 + "</p>";
			this.setRelationResults(sms);
		}
	}
	/**
	 * Checks whether Fedora and Mulgara services are up and running prior to 
	 * enabling performing any operations
	 * 
	 * @return true if both services are running; false otherwise
	 */
	@Override
	public boolean isFedoraMulgaraRunning() {
		try {
			FedoraMulgaraService service = new FedoraMulgaraServiceImpl();
			if (service.isFedoraRunning() && service.isMulgaraRunning())
				return true;
		} catch (JFigException e) {
			logger.error(e.getLocalizedMessage());
			return false;
		}
		return false;
	}
}
